www.gusucode.com > VC++ 基于IE内核功能很齐全的浏览器(支持多标签)-源码程序 > VC++ 基于IE内核功能很齐全的浏览器(支持多标签)-源码程序/code/Explorer/CJMenuBar.cpp
// CJMenuBar.cpp : implementation file // Copyright ? 1998-1999 CodeJock.com, All Rights Reserved. // See ReadMe.txt for TERMS OF USE. // // Based on the code written by Paul DiLascia for MSJ. // ///////////////////////////////////////////////////////////////////////////// /**************************************************************************** * * $Date: 10/24/99 9:12p $ * $Revision: 11 $ * $Archive: /CodeJock/CJLibrary/CJMenuBar.cpp $ * * $History: CJMenuBar.cpp $ * * ***************** Version 11 ***************** * User: Kirk Stowell Date: 10/24/99 Time: 9:12p * Updated in $/CodeJock/CJLibrary * Fixed potential resource and memory leak problems. * * ***************** Version 10 ***************** * User: Kirk Stowell Date: 8/31/99 Time: 1:11a * Updated in $/CodeJockey/CJLibrary * Updated copyright and contact information. * * ***************** Version 9 ***************** * User: Kirk Stowell Date: 8/29/99 Time: 9:36p * Updated in $/CodeJockey/CJLibrary * Fixed bug with left arrow tracking - Tim Lewis <timlewis@home.com> * * ***************** Version 8 ***************** * User: Kirk Stowell Date: 8/29/99 Time: 9:14p * Updated in $/CodeJockey/CJLibrary * Added Unicode compliance, thanks to Barry Burton for his help with * this. * * * ***************** Version 7 ***************** * User: Kirk Stowell Date: 6/23/99 Time: 12:04a * Updated in $/CodeJockey/CJLibrary * * ***************** Version 6 ***************** * User: Kirk Stowell Date: 7/25/99 Time: 10:00p * Updated in $/CodeJockey/CJLibrary * * ***************** Version 5 ***************** * User: Kirk Stowell Date: 7/25/99 Time: 12:30a * Updated in $/CodeJockey/CJLibrary * * ***************** Version 4 ***************** * User: Kirk Stowell Date: 7/25/99 Time: 12:15a * Updated in $/CodeJockey/CJLibrary * * ***************** Version 3 ***************** * User: Kirk Stowell Date: 6/23/99 Time: 12:33a * Updated in $/CodeJockey/CJLibrary * * ***************** Version 2 ***************** * User: Kirk Stowell Date: 7/18/99 Time: 10:28p * Updated in $/CodeJockey/CJLibrary * Further cleanup to handle CCJMenu class. * * ***************** Version 1 ***************** * User: Kirk Stowell Date: 7/15/99 Time: 12:34a * Created in $/CodeJockey/CJLibrary * Initial creation. Extended the original class written by Paul DiLascia * for MSJ. Class uses CCJMenu and fixes some bugs with the original * class. * ***************************************************************************/ ///////////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "CJMenuBar.h" #include "CJMenu.h" // CCJMenu class declaration #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ///////////////////////////////////////////////////////////////////////////// // CCJMenuBar CCJMenuBar::CCJMenuBar() { m_iTrackingState = TRACK_NONE; // initial state: not tracking m_iPopupTracking = -1; m_iNewPopup = -1; // invalid m_bAutoRemoveFrameMenu = TRUE; // set frame's menu to NULL } CCJMenuBar::~CCJMenuBar() { // fix potential resource leak - KStowell - 10-15-99 m_Font.DeleteObject(); } IMPLEMENT_DYNAMIC(CCJMenuBar, CCJToolBar) BEGIN_MESSAGE_MAP(CCJMenuBar, CCJToolBar) //{{AFX_MSG_MAP(CCJMenuBar) ON_WM_LBUTTONDOWN() ON_WM_MOUSEMOVE() ON_WM_SIZE() ON_UPDATE_COMMAND_UI_RANGE(0, 256, OnUpdateMenuButton) //}}AFX_MSG_MAP END_MESSAGE_MAP() BOOL CCJMenuBar::Create(CWnd* pParentWnd, DWORD dwStyle, UINT nID) { return CreateEx(pParentWnd, NULL, dwStyle, CRect(m_cxLeftBorder, m_cyTopBorder, m_cxRightBorder, m_cyBottomBorder), nID); } BOOL CCJMenuBar::CreateEx(CWnd* pParentWnd, DWORD dwCtrlStyle, DWORD dwStyle, CRect rcBorders, UINT nID) { if( !CCJToolBar::CreateEx( pParentWnd, dwCtrlStyle, dwStyle, rcBorders, nID)) return FALSE; UpdateFont(); m_frameHook.Install(this, *pParentWnd); SetWindowText(_T("Menu Bar")); return TRUE; } ///////////////////////////////////////////////////////////////////////////// // CCJMenuBar message handlers CSize CCJMenuBar::CalcFixedLayout(BOOL bStretch, BOOL bHorz) { if( m_bInReBar ) { return CCJToolBar::CalcFixedLayout(bStretch, bHorz); } else { CSize size = CCJToolBar::CalcFixedLayout(bStretch, bHorz); CRect rcClient; GetParentFrame()->GetClientRect(&rcClient); if( bHorz ) { size.cx = rcClient.Width(); } else { size.cy = rcClient.Height(); } return size; } } ////////////////// // Set menu bar font from current system menu font // void CCJMenuBar::UpdateFont() { m_Font.DeleteObject(); NONCLIENTMETRICS ncm; ncm.cbSize = sizeof(ncm); SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0); VERIFY(m_Font.CreateFontIndirect(&ncm.lfMenuFont)); SetFont(&m_Font); } ////////////////// // The reason for having this is so MFC won't automatically disable // the menu buttons. Assumes < 256 top-level menu items. The ID of // the ith menu button is i. IOW, the index and ID are the same. // void CCJMenuBar::OnUpdateMenuButton(CCmdUI* pCmdUI) { ASSERT_VALID(this); if (IsValidButton(pCmdUI->m_nID)) pCmdUI->Enable(TRUE); } ////////////////// // Recompute layout of menu bar // void CCJMenuBar::RecomputeMenuLayout() { SetWindowPos(NULL, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER); } ////////////////// // Make frame recalculate control bar sizes after menu change // void CCJMenuBar::RecomputeToolbarSize() { // Force toolbar to recompute size CFrameWnd* pFrame = (CFrameWnd*)GetParentFrame(); ASSERT_VALID(pFrame); ASSERT(pFrame->IsFrameWnd()); pFrame->RecalcLayout(); // floating frame pFrame = GetParentFrame(); if (pFrame->IsKindOf(RUNTIME_CLASS(CMiniFrameWnd))) pFrame->RecalcLayout(); } ////////////////// // Set tracking state: none, button, or popup // void CCJMenuBar::SetTrackingState(TRACKINGSTATE iState, int iButton) { ASSERT_VALID(this); if (iState != m_iTrackingState) { if (iState == TRACK_NONE) iButton = -1; SetHotItem(iButton); // could be none (-1) if (iState==TRACK_POPUP) { // set related state stuff m_bEscapeWasPressed = FALSE; // assume Esc key not pressed m_bProcessRightArrow = // assume left/right arrow.. m_bProcessLeftArrow = TRUE; // ..will move to prev/next popup m_iPopupTracking = iButton; // which popup I'm tracking } m_iTrackingState = iState; } } ////////////////// // Toggle state from home state to button-tracking and back // void CCJMenuBar::ToggleTrackButtonMode() { ASSERT_VALID(this); if (m_iTrackingState == TRACK_NONE || m_iTrackingState == TRACK_BUTTON) { SetTrackingState(m_iTrackingState == TRACK_NONE ? TRACK_BUTTON : TRACK_NONE, 0); } } ////////////////// // Get button index before/after a given button // int CCJMenuBar::GetNextOrPrevButton(int iButton, BOOL bPrev) { ASSERT_VALID(this); if (bPrev) { iButton--; if (iButton <0) iButton = GetButtonCount() - 1; } else { iButton++; if (iButton >= GetButtonCount()) iButton = 0; } return iButton; } ///////////////// // This is to correct a bug in the system toolbar control: TB_HITTEST only // looks at the buttons, not the size of the window. So it returns a button // hit even if that button is totally outside the size of the window! // int CCJMenuBar::HitTest(CPoint p) const { int iHit = CCJToolBar::HitTest(p); if (iHit>0) { CRect rc; GetClientRect(&rc); if (!rc.PtInRect(p)) // if point is outside window iHit = -1; // can't be a hit! } return iHit; } ////////////////// // Load menu from resource // BOOL CCJMenuBar::LoadMenu(UINT nID) { CFrameWnd* pFrame = GetParentFrame(); ASSERT_VALID(pFrame); pFrame->GetMenu()->DestroyMenu(); pFrame->SetMenu(NULL); CMenu menu; menu.LoadMenu(nID); m_nMenuID = nID; // delete existing buttons int nCount = GetButtonCount(); while (nCount--) { VERIFY(DeleteButton(0)); } DWORD dwStyle = GetStyle(); BOOL bModifyStyle = ModifyStyle(0, TBSTYLE_FLAT|TBSTYLE_TRANSPARENT); SetImageList(NULL); UINT nMenuItems = menu.GetMenuItemCount(); for( UINT i = 0; i < nMenuItems; i++ ) { CString strName; if( menu.GetMenuString(i, strName, MF_BYPOSITION )) { TBBUTTON tbb; memset( &tbb, 0, sizeof( TBBUTTON )); tbb.idCommand = menu.GetMenuItemID(i); // Because the toolbar is too brain-damaged to know if it already has // a string, and is also too brain-dead to even let you delete strings, // I have to determine if each string has been added already. Otherwise // in a MDI app, as the menus are repeatedly switched between doc and // no-doc menus, I will keep adding strings until somebody runs out of // memory. Sheesh! // int iString = -1; for (int j=0; j<m_arStrings.GetSize(); j++) { if (m_arStrings[j] == strName) { iString = j; // found it break; } } if (iString <0) { // string not found: add it iString = AddStrings(strName); m_arStrings.SetAtGrow(iString, strName); } tbb.iString = iString; tbb.fsState = TBSTATE_ENABLED; tbb.fsStyle = TBSTYLE_AUTOSIZE; tbb.iBitmap = -1; tbb.idCommand = i; VERIFY(AddButtons(1, &tbb)); } } if( bModifyStyle ) { SetWindowLong(m_hWnd, GWL_STYLE, dwStyle); } if( ::IsMenu( menu )) { AutoSize(); // size buttons RecomputeToolbarSize(); // and menubar itself } menu.DestroyMenu(); return TRUE; } ////////////////// // Handle mouse click: if clicked on button, press it // and go into main menu loop. // void CCJMenuBar::OnLButtonDown(UINT nFlags, CPoint pt) { ASSERT_VALID(this); int iButton = HitTest(pt); if (iButton >= 0 && iButton<GetButtonCount()) // if mouse is over a button: TrackPopup(iButton); // track it else // otherwise: CCJToolBar::OnLButtonDown(nFlags, pt); // pass it on... } ////////////////// // Handle mouse movement // void CCJMenuBar::OnMouseMove(UINT nFlags, CPoint pt) { ASSERT_VALID(this); if (m_iTrackingState==TRACK_BUTTON) { // In button-tracking state, ignore mouse-over to non-button area. // Normally, the toolbar would de-select the hot item in this case. // // Only change the hot item if the mouse has actually moved. // This is necessary to avoid a bug where the user moves to a different // button from the one the mouse is over, and presses arrow-down to get // the menu, then Esc to cancel it. Without this code, the button will // jump to wherever the mouse is--not right. int iHot = HitTest(pt); if (IsValidButton(iHot) && pt != m_ptMouse) SetHotItem(iHot); return; // don't let toolbar get it } m_ptMouse = pt; // remember point CCJToolBar::OnMouseMove(nFlags, pt); } ////////////////// // Window was resized: need to recompute layout // void CCJMenuBar::OnSize(UINT nType, int cx, int cy) { CCJToolBar::OnSize(nType, cx, cy); RecomputeMenuLayout(); } ////////////////// // Bar style changed: eg, moved from left to right dock or floating // void CCJMenuBar::OnBarStyleChange(DWORD dwOldStyle, DWORD dwNewStyle) { CCJToolBar::OnBarStyleChange(dwOldStyle, dwNewStyle); RecomputeMenuLayout(); } ///////////////// // When user selects a new menu item, note whether it has a submenu // and/or parent menu, so I know whether right/left arrow should // move to the next popup. // void CCJMenuBar::OnMenuSelect(HMENU hmenu, UINT iItem) { if (m_iTrackingState > 0) { // process right-arrow if item is NOT a submenu m_bProcessRightArrow = (::GetSubMenu(hmenu, iItem) == NULL); // process left-arrow if curent menu is one I'm tracking m_bProcessLeftArrow = TRUE; } } // globals--yuk! But no other way using windows hooks. // static CCJMenuBar* g_pMenuBar = NULL; static HHOOK g_hMsgHook = NULL; //////////////// // Menu filter hook just passes to virtual CCJMenuBar function // LRESULT CALLBACK CCJMenuBar::MenuInputFilter(int code, WPARAM wp, LPARAM lp) { return (code==MSGF_MENU && g_pMenuBar && g_pMenuBar->OnMenuInput(*((MSG*)lp))) ? TRUE : CallNextHookEx(g_hMsgHook, code, wp, lp); } ////////////////// // Handle menu input event: Look for left/right to change popup menu, // mouse movement over over a different menu button for "hot" popup effect. // Returns TRUE if message handled (to eat it). // BOOL CCJMenuBar::OnMenuInput(MSG& m) { ASSERT_VALID(this); ASSERT(m_iTrackingState == TRACK_POPUP); // sanity check int msg = m.message; if (msg==WM_KEYDOWN) { // handle left/right-arow. TCHAR vkey = static_cast<TCHAR>(m.wParam); if ((vkey == VK_LEFT && m_bProcessLeftArrow) || (vkey == VK_RIGHT && m_bProcessRightArrow)) { CancelMenuAndTrackNewOne( GetNextOrPrevButton(m_iPopupTracking, vkey==VK_LEFT)); return TRUE; // eat it } else if (vkey == VK_ESCAPE) { m_bEscapeWasPressed = TRUE; // (menu will abort itself) } } else if (msg==WM_MOUSEMOVE || msg==WM_LBUTTONDOWN) { // handle mouse move or click CPoint pt = m.lParam; ScreenToClient(&pt); if (msg == WM_MOUSEMOVE) { if (pt != m_ptMouse) { int iButton = HitTest(pt); if (IsValidButton(iButton) && iButton != m_iPopupTracking) { // user moved mouse over a different button: track its popup CancelMenuAndTrackNewOne(iButton); } m_ptMouse = pt; } } else if (msg == WM_LBUTTONDOWN) { if (HitTest(pt) == m_iPopupTracking) { // user clicked on same button I am tracking: cancel menu CancelMenuAndTrackNewOne(-1); return TRUE; // eat it } } } return FALSE; // not handled } ////////////////// // Cancel the current popup menu by posting WM_CANCELMODE, and track a new // menu. iNewPopup is which new popup to track (-1 to quit). // void CCJMenuBar::CancelMenuAndTrackNewOne(int iNewPopup) { ASSERT_VALID(this); if (iNewPopup != m_iPopupTracking) { GetParentFrame()->PostMessage(WM_CANCELMODE); // quit menu loop m_iNewPopup = iNewPopup; // go to this popup (-1 = quit) } } ////////////////// // Track the popup submenu associated with the i'th button in the menu bar. // This fn actually goes into a loop, tracking different menus until the user // selects a command or exits the menu. // void CCJMenuBar::TrackPopup(int iButton) { ASSERT_VALID(this); m_popupMenu.LoadMenu(m_nMenuID); m_popupMenu.LoadToolbar(m_nMenuID); ASSERT(::IsMenu(m_popupMenu)); while (iButton >= 0) { // while user selects another menu m_iNewPopup = -1; // assume quit after this PressButton(iButton, TRUE); // press the button UpdateWindow(); // and force repaint now // post a simulated arrow-down into the message stream // so TrackPopupMenu will read it and move to the first item GetParentFrame()->PostMessage(WM_KEYDOWN, VK_DOWN, 1); GetParentFrame()->PostMessage(WM_KEYUP, VK_DOWN, 1); SetTrackingState(TRACK_POPUP, iButton); // enter tracking state // Need to install a hook to trap menu input in order to make // left/right-arrow keys and "hot" mouse tracking work. // ASSERT(g_pMenuBar == NULL); g_pMenuBar = this; ASSERT(g_hMsgHook == NULL); g_hMsgHook = SetWindowsHookEx(WH_MSGFILTER, MenuInputFilter, NULL, ::GetCurrentThreadId()); // get submenu and display it beneath button TPMPARAMS tpm; CRect rcButton; GetRect(iButton, rcButton); ClientToScreen(&rcButton); CPoint pt = ComputeMenuTrackPoint(rcButton, tpm); CCJMenu* pPopupMenu = (CCJMenu*)m_popupMenu.GetSubMenu(iButton); #if 0//Ϊ??IE?????? if(iButton==3) { TCHAR sz[MAX_PATH]; TCHAR szPath[MAX_PATH]; HKEY hKey; DWORD dwSize; //CMenu* pFMenu; //pPopupMenu = m_menuMainfrm.GetSubMenu(3); //while(pFMenu->DeleteMenu(0, MF_BYPOSITION)); // ??ע????в????ղؼ????? if(RegOpenKey(HKEY_CURRENT_USER, _T("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\User Shell Folders"), &hKey) != ERROR_SUCCESS) { TRACE0("Favorites folder not found\n"); return ; } dwSize = sizeof(sz); RegQueryValueEx(hKey, _T("Favorites"), NULL, NULL, (LPBYTE)sz, &dwSize); ExpandEnvironmentStrings(sz, szPath, MAX_PATH); RegCloseKey(hKey); //?????ղؼв˵? BuildFavoritesMenu(szPath, 0, pPopupMenu); } #endif pPopupMenu->TrackPopupMenu( TPM_LEFTALIGN|TPM_LEFTBUTTON|TPM_VERTICAL, pt.x, pt.y, GetParentFrame()); // uninstall hook. ::UnhookWindowsHookEx(g_hMsgHook); g_hMsgHook = NULL; g_pMenuBar = NULL; PressButton(iButton, FALSE); // un-press button UpdateWindow(); // and force repaint now // If the user exited the menu loop by pressing Escape, // return to track-button state; otherwise normal non-tracking state. SetTrackingState(m_bEscapeWasPressed ? TRACK_BUTTON : TRACK_NONE, iButton); // If the user moved mouse to a new top-level popup (eg from File to // Edit button), I will have posted a WM_CANCELMODE to quit // the first popup, and set m_iNewPopup to the new menu to show. // Otherwise, m_iNewPopup will be -1 as set above. // So just set iButton to the next popup menu and keep looping... iButton = m_iNewPopup; } // fix potential resource leak - KStowell - 10-15-99 m_popupMenu.DestroyMenu(); } ////////////////// // Given button rectangle, compute point and "exclude rect" for // TrackPopupMenu, based on current docking style, so that the menu will // appear always inside the window. // CPoint CCJMenuBar::ComputeMenuTrackPoint(const CRect& rcButn, TPMPARAMS& tpm) { tpm.cbSize = sizeof(tpm); DWORD dwStyle = m_dwStyle; CPoint pt; CRect& rcExclude = (CRect&)tpm.rcExclude; rcExclude = rcButn; ::GetWindowRect(::GetDesktopWindow(), &rcExclude); switch (dwStyle & CBRS_ALIGN_ANY) { case CBRS_ALIGN_BOTTOM: pt = CPoint(rcButn.left, rcButn.top); rcExclude.top = rcButn.top; break; case CBRS_ALIGN_LEFT: pt = CPoint(rcButn.right, rcButn.top); rcExclude.right = rcButn.right; break; case CBRS_ALIGN_RIGHT: pt = CPoint(rcButn.left, rcButn.top); rcExclude.left = rcButn.left; break; default: // case CBRS_ALIGN_TOP: pt = CPoint(rcButn.left, rcButn.bottom); break; } return pt; } ////////////////// // This function translates special menu keys and mouse actions. // You must call it from your frame's PreTranslateMessage. // BOOL CCJMenuBar::TranslateFrameMessage(MSG* pMsg) { ASSERT_VALID(this); ASSERT(pMsg); UINT msg = pMsg->message; if (WM_LBUTTONDOWN <= msg && msg <= WM_MOUSELAST) { if (pMsg->hwnd != m_hWnd && m_iTrackingState > 0) { // user clicked outside menu bar: exit tracking mode SetTrackingState(TRACK_NONE); } } else if (msg==WM_SYSKEYDOWN || msg==WM_SYSKEYUP || msg==WM_KEYDOWN) { TCHAR vkey = static_cast<TCHAR>(pMsg->wParam); // get virt key BOOL bAlt = HIWORD(pMsg->lParam) & KF_ALTDOWN; // Alt key down if (vkey==VK_MENU || (vkey==VK_F10 && !((GetKeyState(VK_SHIFT) & 0x80000000) || (GetKeyState(VK_CONTROL) & 0x80000000) || bAlt))) { // key is VK_MENU or F10 with no alt/ctrl/shift: toggle menu mode if (msg==WM_SYSKEYUP) { ToggleTrackButtonMode(); } return TRUE; } else if ((msg==WM_SYSKEYDOWN || msg==WM_KEYDOWN)) { if (m_iTrackingState == TRACK_BUTTON) { // I am tracking: handle left/right/up/down/space/Esc switch (vkey) { case VK_LEFT: case VK_RIGHT: // left or right-arrow: change hot button if tracking buttons SetHotItem(GetNextOrPrevButton(GetHotItem(), vkey==VK_LEFT)); return TRUE; case VK_SPACE: // (personally, I like SPACE to enter menu too) case VK_UP: case VK_DOWN: // up or down-arrow: move into current menu, if any TrackPopup(GetHotItem()); return TRUE; case VK_ESCAPE: // escape key: exit tracking mode SetTrackingState(TRACK_NONE); return TRUE; } } // Handle alphanumeric key: invoke menu. Note that Alt-X // chars come through as WM_SYSKEYDOWN, plain X as WM_KEYDOWN. if ((bAlt || m_iTrackingState == TRACK_BUTTON) && isalnum(vkey)) { // Alt-X, or else X while in tracking mode UINT nID; if (MapAccelerator(vkey, nID)) { TrackPopup(nID); // found menu mnemonic: track it return TRUE; // handled } else if (m_iTrackingState==TRACK_BUTTON && !bAlt) { MessageBeep(0); return TRUE; } } // Default for any key not handled so far: return to no-menu state if (m_iTrackingState > 0) { SetTrackingState(TRACK_NONE); } } } return FALSE; // not handled, pass along } #ifdef _DEBUG void CCJMenuBar::AssertValid() const { CCJToolBar::AssertValid(); ASSERT(TRACK_NONE<=m_iTrackingState && m_iTrackingState<=TRACK_POPUP); m_frameHook.AssertValid(); } void CCJMenuBar::Dump(CDumpContext& dc) const { CCJToolBar::Dump(dc); } #endif ////////////////////////////////////////////////////////////////// // CCJMenuBarFrameHook is used to trap menu-related messages sent to the owning // frame. The same class is also used to trap messages sent to the MDI client // window in an MDI app. I should really use two classes for this, // but it uses less code to chare the same class. Note however: there // are two different INSTANCES of CCJMenuBarFrameHook in CCJMenuBar: one for // the frame and one for the MDI client window. // CCJMenuBarFrameHook::CCJMenuBarFrameHook() { } CCJMenuBarFrameHook::~CCJMenuBarFrameHook() { HookWindow((HWND)NULL); // (unhook) } ////////////////// // Install hook to trap window messages sent to frame or MDI client. // BOOL CCJMenuBarFrameHook::Install(CCJMenuBar* pMenuBar, HWND hWndToHook) { ASSERT_VALID(pMenuBar); m_pMenuBar = pMenuBar; return HookWindow(hWndToHook); } ////////////////////////////////////////////////////////////////// // Trap frame/MDI client messages specific to menubar. // LRESULT CCJMenuBarFrameHook::WindowProc(UINT msg, WPARAM wp, LPARAM lp) { CCJMenuBar& mb = *m_pMenuBar; switch (msg) { // The following messages are trapped for the frame window case WM_SYSCOLORCHANGE: mb.UpdateFont(); break; case WM_MENUSELECT: mb.OnMenuSelect((HMENU)lp, (UINT)LOWORD(wp)); break; } return CSubclassWnd::WindowProc(msg, wp, lp); }